package rpc;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * RPC 的 Server端
 * 
 * @author 宋挺
 */
public class RPCServer {
	/** Server端的 ServerSocket实例 */
	private ServerSocket server;
	/** Server端监听的端口 */
	private int port;
	/** Server端 RPC协议接口的实现缓存, 一个接口对应一个实现类的实例 */
	private static Map<Class<?>, Object> intfaceImpls = new HashMap<Class<?>, Object>();
	/** 处理 RPC请求的线程池 */
	ExecutorService threadPool;

	/**
	 * 构造一个 RPC 的 Server端实例
	 * 
	 * @param intface
	 *            RPC协议接口的 Class对象
	 * @param intfaceImpl
	 *            Server端 RPC协议接口的实现
	 * @param port
	 *            Server端监听的端口
	 */
	public <T> RPCServer(Class<T> intface, T intfaceImpl, int port) throws IOException {
		server = new ServerSocket(port);
		this.port = port;
		RPCServer.intfaceImpls.put(intface, intfaceImpl);
	}

	/**
	 * 循环监听并接收 Client端连接, 处理 RPC请求, 向 Client端返回结果
	 */
	public void start() {
		System.out.println("Starting Socket Handler for port " + port);
		threadPool = Executors.newCachedThreadPool();
		try {
			while (true) {
				// 接收 Client端连接, 创建一个 Handler线程, 处理 RPC请求
				// new Handler(server.accept()).start();
				threadPool.execute(new Handler(server.accept()));
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally { // 关闭资源
			threadPool.shutdownNow();
			CloseUtil.closeAll(server);
		}
	}

	/**
	 * 向 RPC协议接口的实现缓存中添加缓存
	 * 
	 * @param intface
	 *            RPC协议接口的 Class对象
	 * @param intfaceImpl
	 *            Server端 RPC协议接口的实现
	 */
	public static <T> void addIntfaceImpl(Class<T> intface, T intfaceImpl) {
		RPCServer.intfaceImpls.put(intface, intfaceImpl);
	}

	/**
	 * 处理 RPC请求的线程类
	 * 
	 * @author 宋挺
	 */
	private static class Handler extends Thread {
		/** Server端接收到的 Client端连接 */
		private Socket client;
		/** 用于接收 client 的 RPC请求的输入流 */
		private ObjectInputStream ois;
		/** 用于向 client 返回 RPC请求结果的输出流 */
		private ObjectOutputStream oos;
		/** RPC请求的封装 */
		private Invocation invocation;

		/**
		 * 用 Client端连接构造 Handler线程
		 * 
		 * @param client
		 */
		public Handler(Socket client) {
			this.client = client;
		}

		@Override
		public void run() {
			try {
				// 打开 client 的输入流
				ois = new ObjectInputStream(client.getInputStream());
				// 反序列化, 从输入流中读取 RPC请求的封装
				invocation = (Invocation) ois.readObject();
				// 从 RPC协议接口的实现缓存中获取实现
				Object intfaceImpl = intfaceImpls.get(invocation.getIntface());
				// 获取 Server端 RPC协议接口的方法实现
				Method method = intfaceImpl.getClass().getMethod(invocation.getMethodName(),
						invocation.getParameterTypes());
				// 跳过安全检查
				method.setAccessible(true);
				// 调用具体的实现方法, 用 res 接收方法返回结果
				Object res = method.invoke(intfaceImpl, invocation.getParams());
				// 打开 client 的输出流
				oos = new ObjectOutputStream(client.getOutputStream());
				// 序列化, 向输出流中写入 RPC请求的结果
				oos.writeObject(res);
				oos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			} catch (SecurityException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} finally { // 关闭资源
				CloseUtil.closeAll(ois, oos);
				CloseUtil.closeAll(client);
			}
		}
	}
}